/********************************************************************************
 * Copyright (c) 2017, 2018 Bosch Connected Devices and Solutions GmbH.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * Contributors:
 *    Bosch Connected Devices and Solutions GmbH - initial contribution
 *
 * SPDX-License-Identifier: EPL-2.0
 ********************************************************************************/

/*
 * generated by Xtext 2.10.0
 */
package org.eclipse.mita.platform.generator

import org.eclipse.mita.platform.SystemSpecification
import com.google.inject.Inject
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.documentation.IEObjectDocumentationProvider
import org.eclipse.xtext.generator.AbstractGenerator
import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.generator.IGeneratorContext
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
import org.eclipse.mita.platform.Platform
import org.eclipse.mita.platform.AbstractSystemResource
import org.eclipse.mita.platform.SystemResourceAlias
import org.eclipse.mita.platform.Signal
import org.eclipse.mita.base.types.Parameter

/**
 * Generates code from your model files on save.
 * 
 * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation
 */
class PlatformDSLGenerator extends AbstractGenerator {

	@Inject
	extension IEObjectDocumentationProvider documentationProvider

	override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
		val platform = resource.contents.filter(SystemSpecification).flatMap[x | x.resources ].filter(Platform).head;
		
		fsa.generateFile('reference.md', '''
		«platform.generateSystemResourecDocumentation»
		''')
	}
	
	private def getParameterDocumentation(Signal item, Parameter parameter) {
		val doc = item.documentation
		if(doc === null) return null;
		
		val paramStart = '''@param «parameter.name»''';
		var start = doc.indexOf(paramStart);
		if(start < 0) return null;
		start += paramStart.length;
		
		var end = doc.indexOf("@param", start);
		end = if(end < 0) doc.length else end;
		
		return doc.substring(start, end).trim;
	}
	
	private def getWithoutParameterDocumentation(String doc) {
		if(doc === null) return null;
		
		val end = doc.indexOf('@param');
		return if(end < 0) {
			doc
		} else {
			doc.substring(0, end).trim;
		}
	}
	
	def generateSystemResourecDocumentation(Platform platform) '''
		«FOR resource : platform.resources»
		## «resource.typeName»: «resource.name»«IF resource instanceof SystemResourceAlias» («resource.delegate.name»)«ENDIF»
		«resource.documentation»
		
		«IF !resource.configurationItems.empty»
		### Configuration Items
		<table>
		    <thead>
		        <tr>
		            <td>Name</td>
		            <td>Description</td>
		        </tr>
		    </thead>
		    <tbody>
				«FOR ci : resource.configurationItems»
				<tr>
					<td><div class="highlight"><pre>«IF !ci.required»<small>optional</small> «ENDIF»<b>«ci.name»</b> : <span class="kt">«ci.type»</span></pre></div></td>
					<td>«IF ci.defaultValue !== null»Defaults to <i>«ci.defaultValue.originalSpec»</i>. «ENDIF»«ci.documentation»</td>
				</tr>
		    	«ENDFOR»
		    </tbody>
		</table>
		«ENDIF»
		
		«IF !resource.modalities.empty»
		#### Modalities
		<table>
		    <thead>
		        <tr>
		            <td>Name</td>
		            <td>Description</td>
		        </tr>
		    </thead>
		    <tbody>
				«FOR mod : resource.modalities»
				<tr>
					<td><div class="highlight"><pre><b>«mod.name»</b> : <span class="kt">«mod.type»</span></pre></div></td>
					<td>«mod.documentation»</td>
				</tr>
		    	«ENDFOR»
		    </tbody>
		</table>
		«ENDIF»
		
		«IF !resource.signals.empty»
		### Variable Configuration Items
		<table>
		    <thead>
		        <tr>
		            <td>Name</td>
		            <td>Description</td>
		            <td>Parameters</td>
		        </tr>
		    </thead>
		    <tbody>
				«FOR mod : resource.signals»
				<tr>
					<td><div class="highlight"><pre><b>«mod.name»</b> : <span class="kt">«mod.type»</span></pre></div></td>
					<td>«mod.documentation.withoutParameterDocumentation»</td>
					<td>
						<ul>
						«FOR param : mod.parameters»
							<li>
								<div class="highlight"><pre>«IF param.optional»<small>optional</small> «ENDIF» <b>«param.name»</b> : <span class="kt">«param.typeSpecifier.originalSpec»</span></pre></div>
								«mod.getParameterDocumentation(param)»
							</li>
						«ENDFOR»
						</ul>
					</td>
				</tr>
		    	«ENDFOR»
		    </tbody>
		</table>
		«ENDIF»
		
		«IF !resource.events.empty»
		#### Events
		<table>
		    <thead>
		        <tr>
		            <td>Name</td>
		            <td>Description</td>
		        </tr>
		    </thead>
		    <tbody>
				«FOR mod : resource.events»
				<tr>
					<td><div class="highlight"><pre><b>«mod.name»</b></pre></div></td>
					<td>«mod.documentation»</td>
				</tr>
		    	«ENDFOR»
		    </tbody>
		</table>
		«ENDIF»

		«ENDFOR»
		'''
	
	def String getTypeName(AbstractSystemResource resource) {
		if(resource instanceof SystemResourceAlias) {
			return resource.delegate.typeName;
		} else {
			resource.eClass.name;
		}
	}
	
	def getOriginalSpec(EObject obj) {
		return NodeModelUtils.findActualNodeFor(obj)?.text?.trim;
	}
	
}
